/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:itsm-gateway
 * Create Time: 2016年1月30日 下午3:02:56
 */
package com.lenovo.lmrp.server.itsmgateway.spi;

import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

import com.fasterxml.jackson.core.type.TypeReference;
import com.lenovo.lmrp.api.itsmgateway.IItsmEngineer;
import com.lenovo.lmrp.api.model.RestResponse;
import com.lenovo.lmrp.api.model.entity.EngineerPO;
import com.lenovo.lmrp.api.model.view.EngineerVO;
import com.lenovo.lmrp.api.model.view.LoginData;
import com.lenovo.lmrp.server.itsmgateway.domain.engineer.EngineerBO;
import com.lenovo.lmrp.server.itsmgateway.domain.engineer.IEngineerRepository;
import com.lenovo.sdc.framework.annotation.RestService;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.ICommonDAO;
import com.lenovo.sdc.framework.dao.RecordFilter;
import com.lenovo.sdc.framework.util.CommonUtil;
import com.lenovo.sdc.framework.util.Condition;
import com.lenovo.sdc.framework.util.Condition.OperatorEnum;
import com.lenovo.sdc.framework.util.Condition.SortEnum;
import com.lenovo.sdc.framework.util.JSONHelper;
import com.lenovo.sdc.framework.util.PageData;
import com.lenovo.sdc.framework.util.Tuple;
import com.lenovo.sdc.framework.util.exception.ErrorCode;
import com.lenovo.sdc.framework.util.exception.TraceableException;

/**
 * Implement IItsmEngineer interface to process all functions about engineer information, for example,
 * Authenticate, update engineer basic information, reset engineer password, etc.
 * 
 * In DDD, this class belong to application layer, it forward external request/command to internal domain layer 
 * to execute business logic. 
 * 
 * @author wujin
 * @version v1.0
 */
@Named
@RestService
@Path("/itsm/v1")
@Consumes("application/json;charset-utf-8")
@Produces("application/json;charset-utf-8")
public class ItsmEngineerImpl implements IItsmEngineer {
    private IEngineerRepository engineerRepository;

    @Inject
    public void set(IEngineerRepository engineerRepository) {
        this.engineerRepository = engineerRepository;
    }

    /**
     * To check engineer whether is a legal user.
     * 
     * To obtain TicketSystemBO instance first base on itsmcode, if not found return error response with ErrorCode.COMM_ERROR
     * Then get EngineerBO instance do authenticate 
     * 
     */
    @Override
    public RestResponse<Integer> authenticate(String itsmCode, LoginData loginData) {
        try {
            EngineerBO bo = engineerRepository.createEngineerBO(itsmCode, loginData.getLoginname());
            Tuple.Pair<Boolean, String> response = bo.authenticate(loginData.getPassword());
            if (response.getOne()) {
                bo.store(engineerRepository);
                return new RestResponse<Integer>(0, "OK", 0);
            }
            else
                return new RestResponse<Integer>(ErrorCode.SECURITY_AUTH_FAILED.getCode(), response.getSecond(), -1);
        }
        catch (TraceableException exp) {
            return new RestResponse<Integer>(exp.getErrorCode().getCode(), exp.getMessage(), -1);
        }
        catch (Exception exp) {
            return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), -1);
        }
    }

    @Override
    public RestResponse<Integer> updateEngineer(String itsmCode, String engineerid, EngineerVO engineerVO) {
        try {
            EngineerBO bo = engineerRepository.createEngineerBO(itsmCode, engineerid);
            Tuple.Pair<Boolean, String> response = bo.update(engineerVO);
            if (response.getOne()) {
                bo.store(engineerRepository);
                return new RestResponse<Integer>(0, "OK", 0);
            }
            else
                return new RestResponse<Integer>(ErrorCode.SECURITY_AUTH_FAILED.getCode(), response.getSecond(), -1);
        }
        catch (TraceableException exp) {
            return new RestResponse<Integer>(exp.getErrorCode().getCode(), exp.getMessage(), -1);
        }
        catch (Exception exp) {
            return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), -1);
        }
    }

    @Override
    public RestResponse<Integer> resetPassword(String itsmcode, String loginName) {
        return null;
    }

    @Override
    public Response getEngineer(String itsmCode, String engineerID) {
        try {
            EngineerBO bo = engineerRepository.createEngineerBO(itsmCode, engineerID);
            EngineerVO vo = bo.getEngineerVO();
            if (CommonUtil.isNullOrEmpty(vo.getEngineerid()))
                return Response
                    .status(404)
                    .entity(new RestResponse<EngineerVO>(ErrorCode.DB_RECORD_NOTFOUND.getCode(), 
                                    "not found " + engineerID,
                                    null))
                    .build();
            else
                return Response.ok().entity(new RestResponse<EngineerVO>(0, "OK", vo)).build();
        }
        catch (Exception exp) {
            return Response.status(500)
                .entity(new RestResponse<EngineerVO>(ErrorCode.DB_QUERY_FAILED.getCode(), exp.getMessage(), null))
                .build();
        }
    }

    @Override
    public RestResponse<List<EngineerVO>> listEngineer(String itsmCode, String condition, int page, int limit,String sorts) {
        Map<String, String> conditions;
        try {
            if (CommonUtil.nonNullAndEmpty(condition))
                conditions = JSONHelper.fromJSON(URLDecoder.decode("{" + condition + "}", "UTF-8"), new TypeReference<Map<String, String>>() {});
            else
                conditions = new HashMap<>();
        }
        catch (Exception exp) {
            throw new TraceableException(ErrorCode.COMM_PARSE_FAILED, exp);
        }
        
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
            RecordFilter filter = new RecordFilter();
            String value = conditions.get("status");
            if (CommonUtil.nonNullAndEmpty(value))
                filter.addCondition(new Condition<String, Object>("status", Integer.parseInt(value)));

            value = conditions.get("name");
            if (CommonUtil.nonNullAndEmpty(value))
                filter.addCondition(new Condition<String, Object>("loginname", "%" + value + "%", OperatorEnum.LIKE));

            value = conditions.get("phone");
            if (CommonUtil.nonNullAndEmpty(value))
                filter.addCondition(new Condition<String, Object>("phone", "%" + value + "%", OperatorEnum.LIKE));
            
            if (CommonUtil.nonNullAndEmpty(sorts)) {
                String[] items = sorts.split(",");
                for (String item : items) {
                    if (item.equals("name"))
                        item = "loginname";
                    filter.addCondition(new Condition<String, Object>(item, "", OperatorEnum.NONE, SortEnum.ASC));
                }
            }
            
            PageData<EngineerPO> pageData = new PageData<>(page, limit, true);
            dao.filteByCondition(EngineerPO.class, filter, pageData);
            
            List<EngineerVO> vos = new ArrayList<>(pageData.getPageData().size());
            for(Iterator<EngineerPO> it = pageData.getPageData().iterator(); it.hasNext(); ) {
                EngineerPO po = it.next();
                
                EngineerVO vo = new EngineerVO();
                vo.setEngineerid(po.getId());
                vo.setEmail(po.getEmail());
                vo.setPhone(po.getPhone());
                vo.setLoginname(po.getId());
                vo.setName(po.getFullName());
                vo.setStatus(po.getStatus().ordinal());
                vos.add(vo);
                it.remove();
            }
            
            return new RestResponse<List<EngineerVO>>(0, "OK", vos);
        }
        catch (Exception exp) {
            return new RestResponse<List<EngineerVO>>(ErrorCode.DB_QUERY_FAILED.getCode(), exp.getMessage(), null);
        }
    }
}
